[Android] Fix Shadow property affecting transform matrix.#32962
[Android] Fix Shadow property affecting transform matrix.#32962Shalini-Ashokan wants to merge 9 commits into
Conversation
|
The test is already added in this PR. This PR test case covers all scenarios of the current issue also. The issues are the same but created PR for platform-specific. I manually ensured the test case. It is working fine. The AI concern is not valid because the test is not added due to the test case addition. Once this PR is merged, that test case covers both issues. |
|
@Shalini-Ashokan could you please duplicate the test for this PR? |
There was a problem hiding this comment.
Pull request overview
Fixes Android behavior where applying Shadow wraps the native view, causing transforms (scale/rotation/translation/anchor) to be applied to the inner view instead of the shadow-drawing wrapper.
Changes:
- Transfer existing transform properties from the inner Android view to the
WrapperViewwhen the container is created (and back when removed). - Add an Android
ResetTransformhelper to clear transforms on the source view after transfer. - Update Android batched initialization to initialize the wrapper when a view is wrapped.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
src/Core/src/Platform/Android/WrapperView.cs |
Transfers transform-related properties between inner view and wrapper on container add/remove. |
src/Core/src/Platform/Android/ViewExtensions.cs |
Adds ResetTransform helper used during transform transfer. |
src/Core/src/Handlers/View/ViewHandler.cs |
Adjusts Android batched initialization to target the wrapper when present. |
| // If the view is wrapped in a WrapperView (for Shadow/Clip), apply batched properties to the wrapper instead. | ||
| var viewToInitialize = pv.Parent is WrapperView ? (PlatformView)pv.Parent : pv; | ||
| viewToInitialize.Initialize(view); | ||
| } | ||
| } |
There was a problem hiding this comment.
MapInitializeBatchedProperties now calls Initialize(view) on the WrapperView when the platform view is wrapped. Android.ViewExtensions.Initialize batches more than transforms (e.g., enabled, minimumHeight, minimumWidth, alpha), but later property updates (e.g., MapIsEnabled, MapMinimumHeight/Width) still target handler.PlatformView (the inner view). This can leave the wrapper and inner view out of sync (notably: if the view starts disabled and is later enabled, the wrapper may remain disabled and continue blocking input). Consider keeping Initialize(view) on the inner PlatformView and then transferring only the transform-related properties (translation/scale/rotation/pivot) to the wrapper (resetting the inner transforms), or otherwise ensure non-transform properties remain applied consistently to the inner view and/or are updated on the wrapper too.
| // If the view is wrapped in a WrapperView (for Shadow/Clip), apply batched properties to the wrapper instead. | |
| var viewToInitialize = pv.Parent is WrapperView ? (PlatformView)pv.Parent : pv; | |
| viewToInitialize.Initialize(view); | |
| } | |
| } | |
| pv.Initialize(view); | |
| if (pv.Parent is WrapperView wrapper) | |
| TransferBatchedTransformsToWrapper(pv, wrapper); | |
| } | |
| } | |
| static void TransferBatchedTransformsToWrapper(PlatformView platformView, WrapperView wrapperView) | |
| { | |
| wrapperView.TranslationX = platformView.TranslationX; | |
| wrapperView.TranslationY = platformView.TranslationY; | |
| wrapperView.ScaleX = platformView.ScaleX; | |
| wrapperView.ScaleY = platformView.ScaleY; | |
| wrapperView.Rotation = platformView.Rotation; | |
| wrapperView.RotationX = platformView.RotationX; | |
| wrapperView.RotationY = platformView.RotationY; | |
| wrapperView.PivotX = platformView.PivotX; | |
| wrapperView.PivotY = platformView.PivotY; | |
| platformView.TranslationX = 0; | |
| platformView.TranslationY = 0; | |
| platformView.ScaleX = 1; | |
| platformView.ScaleY = 1; | |
| platformView.Rotation = 0; | |
| platformView.RotationX = 0; | |
| platformView.RotationY = 0; | |
| platformView.PivotX = 0; | |
| platformView.PivotY = 0; | |
| } |
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.sh | bash -s -- 32962Or
iex "& { $(irm https://raw.githubusercontent.com/dotnet/maui/main/eng/scripts/get-maui-pr.ps1) } 32962" |
@kubaflo, I have added the test cases and verified them. |
|
/azp run maui-pr-uitests |
|
Azure Pipelines successfully started running 1 pipeline(s). |
7638dc1 to
3a719cb
Compare
kubaflo
left a comment
There was a problem hiding this comment.
Could you please review: #32962 (comment)
@kubaflo, I addressed the AI concerns |
Note
Are you waiting for the changes in this PR to be merged?
It would be very helpful if you could test the resulting artifacts from this PR and let us know in a comment if this change resolves your issue. Thank you!
Issue Details
When a Shadow property is applied to any visual element on Android (Border, Label, Image, etc.), transform properties (Scale, Rotation, Translation) do not work correctly.
Root Cause
When a view has a Shadow, Android wraps it in a container that draws the shadow. The problem was that transforms were applied to the content inside the container, so the content would scale/rotate but the shadow stayed in place.
Description of Change
Modified the initialization logic to detect when a view is wrapped in a container and apply transforms to the container instead. This ensures shadows transform together with their content, fixing the issue for all controls that support Shadow properties.
Validated the behavior in the following platforms
Issues Fixed
Fixes #32731
Test case
The test case is included in this PR.
Output ScreenShot
32731-Before-Fix.mov
32731-After-Fix.mov